<template>
    <div class="w100 h100 p-r">
        <div :id="id"></div>
        <div :id="id + '-tooltip'" class="tooltip dn p10 p-a br10"></div>
    </div>
</template>

<script>
import Chart from '../chart.js'
import * as d3 from 'd3'

export default {
    props: {
        id: {
            required: true,
        },
        data: {
            required: true,
        },
        legend: {
            required: true,
        },
        width: {},
        height: {},
    },
    data() {
        return {
            oldIndex: null,
        }
    },
    mounted() {
        this.$nextTick(() => {
            setTimeout(() => {
                this.init(this.data)
            }, 500)
        })
    },
    methods: {
        init(data) {
            const me = this
            /* ----------------------------配置参数------------------------  */
            const chart = new Chart()
            const box = d3.select('#' + this.id)
            box.node().innerHTML = ''
            box.node().style.width = this.width + 'px'
            box.node().style.height = this.height + 'px'
            const config = {
                margins: { top: 120, left: 30, bottom: 20, right: 20 },
                title: '移动的点',
                pointSize: 15,
                animateDuration: 3000,
            }

            chart.box(box)
            chart.margins(config.margins)

            chart.setId(this.id)
            chart.width(this.width)
            chart.height(this.height)
            const nodes = [] //存储围成气泡的节点

            /* ----------------------------建立力模型------------------------  */
            const force = d3
                .forceSimulation()
                .velocityDecay(0.1) //速度衰减
                .alphaDecay(0) //alpha衰变, 0表示不衰减
                .force('collision', d3.forceCollide(config.pointSize + 0.5).strength(0.1)) //以多于5的半径，0.1的强度，设置碰撞力模型

            /* ----------------------------渲染图标题------------------------  */
            chart.renderTitle = function () {
                chart
                    .svg()
                    .append('text')
                    .classed('title', true)
                    .attr('x', chart.width() / 2)
                    .attr('y', 0)
                    .attr('dy', '2em')
                    .text(config.title)
                    .attr('fill', config.textColor)
                    .attr('text-anchor', 'middle')
                    .attr('stroke', config.textColor)
            }

            /* ----------------------------绑定鼠标交互事件------------------------  */
            chart.addMouseOn = function () {
                d3.selectAll('.circleOverlays')
                    .on('mouseover', function (d) {
                        const position = d3.mouse(chart.svg().node())
                        let selector = d3.select(`#${me.id}-tooltip`)
                        selector.node().innerHTML = d.label
                        selector.classed('dn', false)
                        selector.attr('style', `transform:translate(${position[0] + 15}px,${position[1]}px)`)
                    })
                    .on('mouseleave', function (d) {
                        let selector = d3.select(`#${me.id}-tooltip`)
                        selector.classed('dn', true)
                    })
                    .on('mousemove', function () {
                        const position = d3.mouse(chart.svg().node())
                        d3.select(`#${me.id}-tooltip`).attr(
                            'style',
                            `transform:translate(${position[0] + 15}px,${position[1]}px)`,
                        )
                    })
            }

            chart.renderPointer = function () {
                let prevPoint
                for (let i = 0; i < me.data.length; i++) {
                    let item = me.data[i]
                    let point = [
                        (me.width / 2) * (1 - Math.random() * 0.001),
                        (me.height / 2) * (1 - Math.random() * 0.001),
                    ]
                    const newNode = {
                        x: point[0],
                        y: point[1],
                        vx: prevPoint ? (point[0] - prevPoint[0]) * 0.1 : 0,
                        vy: prevPoint ? (point[1] - prevPoint[1]) * 0.1 : 0,
                        ...item,
                    }

                    prevPoint = point
                    let scaleLinear = d3
                        .scaleLinear()
                        .domain([d3.min(data, d => Math.abs(d.value)), d3.max(data, d => Math.abs(d.value))])
                        .range([1, 2])
                    let group = chart
                        .body()
                        .append('g')
                        .data([newNode])
                        .attr('class', 'node')
                        .attr('transform', d => `translate(${d.x},${d.y})`)

                    group
                        .append('circle')
                        .attr('cx', 0)
                        .attr('cy', 0)
                        .attr('fill', d => {
                            let legend = me.legend.filter(obj => obj.id === d.id)[0] || {}
                            return legend.color || 'black'
                        })
                        .attr('r', 1e-6)
                        .transition()
                        .duration(config.animateDuration / 2)
                        .attr('r', config.pointSize * scaleLinear(Math.abs(item.value)))
                    group
                        .append('text')
                        .text(item.value)
                        .attr('fill', 'white')
                        .attr('text-anchor', 'middle')
                        .attr('dominant-baseline', 'middle')
                        .classed('f16', true)
                        .classed('fam', true)
                    group
                        .append('circle')
                        .attr('class', 'circleOverlays')
                        .attr('cx', 0)
                        .attr('cy', 0)
                        .attr('fill', 'transparent')
                        .attr('r', 1e-6)
                        .transition()
                        .duration(config.animateDuration / 2)
                        .attr('r', config.pointSize * scaleLinear(Math.abs(item.value)))

                    nodes.push(newNode) //加入新点，重新绑定nodes
                    force.nodes(nodes)
                }
            }

            /* ----------------------------绑定tick事件------------------------  */

            chart.addForceTick = function () {
                force.on('tick', function () {
                    chart
                        .body()
                        .selectAll('.node')
                        .attr('transform', d => `translate(${d.x},${d.y})`)
                })
            }

            chart.render = function () {
                // chart.renderTitle()

                chart.renderPointer()

                chart.addForceTick()
                // chart.addMouseOn()
            }

            chart.renderChart()
        },
    },
}
</script>

<style lang="scss" scoped>
.tooltip {
    width: 166px;
    background: #ffffff;
    box-shadow: 0px 0px 8px 0px rgba(0, 36, 137, 0.5);
}
</style>
